package ar.edu.utn.frba.disenio.aterrizar.aerolineas;

import java.util.ArrayList;
import java.util.Collections;
import ar.edu.utn.frba.disenio.aterrizar.busquedas.BusquedaFiltrada;
import ar.edu.utn.frba.disenio.aterrizar.busquedas.BusquedaObligatoria;
import ar.edu.utn.frba.disenio.aterrizar.busquedas.CriterioBusqueda;
import ar.edu.utn.frba.disenio.aterrizar.compra.ManagerCompras;
import ar.edu.utn.frba.disenio.aterrizar.excepciones.AerolineaNoExisteException;
import ar.edu.utn.frba.disenio.aterrizar.excepciones.AsientoReservadoPorOtroUsuarioException;
import ar.edu.utn.frba.disenio.aterrizar.excepciones.ReservaNoEncontradaException;
import ar.edu.utn.frba.disenio.aterrizar.excepciones.SobreReservarException;
import ar.edu.utn.frba.disenio.aterrizar.excepciones.UsuarioNoPuedeReservarException;
import ar.edu.utn.frba.disenio.aterrizar.filtros.Clase;
import ar.edu.utn.frba.disenio.aterrizar.filtros.Estado;
import ar.edu.utn.frba.disenio.aterrizar.filtros.Filtro;
import ar.edu.utn.frba.disenio.aterrizar.filtros.Precio;
import ar.edu.utn.frba.disenio.aterrizar.filtros.Ubicacion;
import ar.edu.utn.frba.disenio.aterrizar.orden.Orden;
import ar.edu.utn.frba.disenio.aterrizar.reserva.ManagerReserva;
import ar.edu.utn.frba.disenio.aterrizar.usuario.Usuario;

public class OperadorAerolineas {
	
	private ManagerReserva managerReservas;
	private static OperadorAerolineas instance;
	private ManagerCompras managerCompras;
	private ArrayList<Aerolinea> aerolineas = new ArrayList<Aerolinea>();
	
	private OperadorAerolineas(){	
		this.managerReservas = new ManagerReserva();
		this.managerCompras = new ManagerCompras();
		this.agregarAerolineas();
	}

	public static OperadorAerolineas getInstance(){
		if(instance ==null) {
			instance = new OperadorAerolineas();
		}
		return instance;
	}
	
	private void agregarAerolineas() {
		this.aerolineas.add(new AdapterLanchita());
		this.aerolineas.add(new AdapterOceanic());
	}
	
	public ArrayList<Vuelo> buscarVuelos(CriterioBusqueda busqueda, Filtro unFiltro, Orden unOrden, Usuario usuario){
		ArrayList<Vuelo> resultadoTotal = new ArrayList<Vuelo>();
		
		for(Aerolinea unaAerolinea : this.getAerolineas()){
			BusquedaFiltrada unaBusqueda;
			if(unFiltro != null) unaBusqueda = new Precio(unFiltro.precioDesde,unFiltro.precioHasta,new Clase(unFiltro.clases, new Ubicacion(unFiltro.ubicacion, new Estado(unFiltro.estado, busqueda, this.managerReservas ,new BusquedaObligatoria(unaAerolinea, busqueda, usuario)))));	
			else unaBusqueda = new BusquedaObligatoria(unaAerolinea, busqueda, usuario);
			
			ArrayList<Vuelo> resultado = unaBusqueda.buscarVuelos();
			resultadoTotal.addAll(resultado);
		}
		
		if(unOrden != null) Collections.sort(resultadoTotal, unOrden);
				
		usuario.agregarBusquedaEstadistica(resultadoTotal);
		return resultadoTotal;
	}		
	
	public void comprarAsiento(Vuelo unVuelo, Usuario usuario){
		
		Aerolinea aerolinea = this.getAerolineaVuelo(unVuelo);
		aerolinea.comprarAsiento(unVuelo.codigo, usuario);
		usuario.agregarCompraRealizada(unVuelo);
		unVuelo.registrarCompra(usuario);
		managerCompras.agregarCompra(unVuelo);
		
		/* 
		 * ESTE CODIGO SERIA SI LE DIERAMOS PELOTA A QUE EL CLIENTE QUE QUIERE COMPRAR ALGO
		 *  RESERVADO, SOLO PUEDA SI ES EL CHABON QUE RESERVO ESE VUELO (NO SOBRERESERVA) 
		 
		if(unVuelo.reservas.isEmpty() || unVuelo.reservas.get(0).usuario.equals(usuario)){
			Aerolinea aerolinea = this.getAerolineaVuelo(unVuelo);
			aerolinea.comprarAsiento(unVuelo.codigo, usuario);
			usuario.agregarCompraRealizada(unVuelo);
			unVuelo.registrarCompra(usuario);
			managerCompras.agregarCompra(unVuelo);
		}else{
			throw new AsientoReservadoPorOtroUsuarioException();
		}
		
		*/
	}
	
	public void reservar(Vuelo unVuelo, Usuario usuario){
		
		if(usuario.podesReservar()){
		
			try{
				this.managerReservas.buscarVueloReservado(unVuelo.codigo);
				throw new SobreReservarException(unVuelo.codigo);
			}catch(ReservaNoEncontradaException e){
				Aerolinea aerolinea = this.getAerolineaVuelo(unVuelo);
				aerolinea.reservar(unVuelo.codigo, usuario);
				usuario.agregarReservaRealizada(unVuelo);
				this.managerReservas.agregarReserva(unVuelo, usuario);
			}			
		}
		else{
			throw new UsuarioNoPuedeReservarException();
		}
	}
	
	public void sobreReservar(Vuelo unVuelo, Usuario usuario){
		this.managerReservas.agregarSobreReserva(unVuelo.codigo, usuario);
		usuario.agregarReservaRealizada(unVuelo);
	}
	
	private Aerolinea getAerolineaVuelo(Vuelo unVuelo){
		for(Aerolinea aerolinea : aerolineas){
			if(aerolinea.nombreAerolinea.equals(unVuelo.getAerolinea())){
				return aerolinea;
			}
		}
		throw new AerolineaNoExisteException();
	}
	
	public void setAerolineaMock(Aerolinea aerolinea) {
		this.aerolineas.clear();
		this.aerolineas.add(aerolinea);
	}
	
	public ManagerReserva getManagerReservas() {
		return managerReservas;
	}

	public void setManagerReservas(ManagerReserva managerReservas) {
		this.managerReservas = managerReservas;
	}

	public ManagerCompras getManagerCompras() {
		return managerCompras;
	}

	public void setManagerCompras(ManagerCompras managerCompras) {
		this.managerCompras = managerCompras;
	}

	public ArrayList<Aerolinea> getAerolineas() {
		return aerolineas;
	}

	public void setAerolineas(ArrayList<Aerolinea> aerolineas) {
		this.aerolineas = aerolineas;
	}
}
